﻿/*  (c) 2008 Benjamin Schroeter
 *  You are allowed to use this code in all your commercial, non-commercial, open and closed source projects.
 *  But you have to leave this Copyright message in all files. This code is provided "as is" without warranty of any kind.
 *  If you have any enhancements or bug reports I will appreciate a short feedback.
 *  For more information visit the article to this code on my blog at 
 *  http://www.ticklishtechs.net/2008/04/12/to-restrict-dynamically-the-usage-of-domain-properties-in-dsl-models/ */

using System;
using System.Collections.Generic;
using System.ComponentModel;
using Microsoft.VisualStudio.Modeling;

namespace BenjaminSchroeter.Dsl.UserRestrictions
{
    /// <summary>
    /// This provider adds the functionality of dynamically restricted
    /// properties to ModelElements.
    /// </summary>
    public class UserRestrictionProvider : TypeDescriptionProvider
    {
        private readonly TypeDescriptionProvider parent;

        /// <summary>
        /// Initializes a new instance of the <see cref="UserRestrictionProvider"/> class.
        /// </summary>
        /// <param name="parent">The parent type description provider.</param>
        private UserRestrictionProvider(TypeDescriptionProvider parent) : base(parent)
        {
            this.parent = parent;
        }

        /// <summary>
        /// Gets a custom type descriptor for the given type and object.
        /// </summary>
        /// <param name="objectType">The type of object for which to retrieve the type descriptor.</param>
        /// <param name="instance">An instance of the type. Can be null if no instance was passed to the <see cref="T:System.ComponentModel.TypeDescriptor"/>.</param>
        /// <returns>
        /// An <see cref="T:System.ComponentModel.ICustomTypeDescriptor"/> that can provide metadata for the type.
        /// </returns>
        public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
        {
            ModelElement e = instance as ModelElement;
            if ( e != null )
                return new RestrictedShapeTypeDescriptor(GetRestrictionMode(e.Store), instance, parent);
               
            return parent.GetTypeDescriptor(objectType, instance);
        }

        /// <summary>
        /// Registers the restricted element.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public static void RegisterRestrictedElement<T>() where T : ModelElement
        {            
            TypeDescriptionProvider baseprovider = TypeDescriptor.GetProvider(typeof(T));
            TypeDescriptor.AddProvider(new UserRestrictionProvider(baseprovider), typeof(T));
        }

        #region get and set restriction modes
        private static readonly Dictionary<Guid, int> restrictions = new Dictionary<Guid, int>();
        
        /// <summary>
        /// Gets the restriction mode for the given store (and so for the diagram / model of this store)..
        /// </summary>
        /// <param name="store">The store of the diagram or model or modelelement.</param>
        /// <returns>The restriction value, if the store is unknown by the UserRestrictionProvider 0 will be returend.</returns>
        public static int GetRestrictionMode(Store store)
        {
            if (restrictions.ContainsKey(store.Id))
                return restrictions[store.Id];

            return 0;
        }

        /// <summary>
        /// Sets the restriction mode for the given store (and so for the diagram / model of this store).
        /// </summary>
        /// <param name="store">The store of the diagram or model or modelelement.</param>
        /// <param name="restriction">The restriction value.</param>
        public static void SetRestrictionMode(Store store,int restriction)
        {
            restrictions[store.Id] = restriction;
        }
        #endregion
    }
}
